perf: PostToolUse hook optimization (~200ms → <30ms)#35
Open
KRRT7 wants to merge 8 commits into
Open
Conversation
Check WARP_CLI_AGENT_PROTOCOL_VERSION before sourcing any files. In non-Warp terminals, subagents, and CI this avoids the cost of SCRIPT_DIR resolution, sourcing should-use-structured.sh, and calling the function — saving ~10-15ms per tool call in those envs.
Replace the subprocess call to warp-notify.sh with an inline printf. This eliminates a bash spawn, a second source of should-use-structured.sh, and a redundant should_use_structured() call — saving ~20-30ms per PostToolUse invocation.
Replace sourcing build-payload.sh (which spawns jq 3 times for session_id, cwd, and payload construction) plus the tool_name extraction (1 more jq) with a single jq -nc call that reads stdin and builds the entire payload in one process. Saves ~60ms per PostToolUse invocation (3 fewer process spawns at ~20ms each). Protocol version negotiation is inlined as a simple bash comparison since the plugin version is a constant (1).
The printf to /dev/tty blocks synchronously when Warp's PTY is congested during heavy screen rendering, causing 2000-2200ms spikes. Backgrounding the write makes the hook return immediately regardless of terminal render state. The notification is fire-and-forget — no response is expected.
- Guard against non-numeric WARP_CLI_AGENT_PROTOCOL_VERSION with
regex check — prevents jq --argjson crash on garbage input.
- Use jq sub(".*/"; "") instead of split/last — correctly returns ""
for root "/" rather than split artifact.
- Remove redundant comments; the commit history explains the "why".
Add 16 tests covering: - Full payload construction (all fields) - Missing/empty fields produce empty strings - Protocol version negotiation (capped at 1, non-numeric fallback) - Early exit paths (no env var, broken Warp version) Uses `script` command to capture /dev/tty output from the real hook script, then extracts and validates the JSON payload. Coverage for on-post-tool-use.sh: 6.7% → 80.0%
Script fixes:
- Strip trailing slashes before extracting project name via
sub("/+$"; "") — matches basename behavior for paths like
"/Users/alice/project/".
- Add 2>/dev/null on jq call to suppress stderr noise.
- Guard against empty BODY (jq failure on malformed stdin) —
exit before sending broken OSC sequence.
Test fixes:
- Use temp file for input instead of echo interpolation (prevents
shell injection if input contains single quotes).
- Add `wait` before sleep to ensure background printf completes.
- Increase sleep to 0.2s for CI robustness.
- Add test for trailing slash in cwd.
Author
Screen.Recording.2026-05-07.at.2.38.01.PM.mov |
harryalbert
reviewed
May 7, 2026
Contributor
harryalbert
left a comment
There was a problem hiding this comment.
Screen.Recording.2026-05-07.at.2.38.01.PM.mov
hmm, the demo looks a little off. It looks like the done notifications flickers on and then goes away, and then I'm not seeing the claude status change to completed (the little check in the vertical tabs status bar) when it's completed. Am I missing something/are these pre-existing issues?
Author
|
I just ran it from the main version and I see flickering still |
Contributor
Hmm, I'm not seeing flickering when I run using the global plugin Screen.Recording.2026-05-07.at.4.04.01.PM.mov |
Author
|
I think I know why it's happening, let me debug rq |
skspade
added a commit
to skspade/claude-code-warp
that referenced
this pull request
May 13, 2026
skspade
added a commit
to skspade/claude-code-warp
that referenced
this pull request
May 13, 2026
Resolution: took pr-27's version of on-post-tool-use.sh and test-hooks.sh. This sacrifices warpdotdev#35's PostToolUse-specific perf inline-jq optimization (which used a direct /dev/tty write, bypassing warpdotdev#44's tty walker) in favor of using the patched warp-notify.sh helper, plus gains tool_preview and permission_mode fields.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
End-to-end optimization of the
PostToolUsehook, which fires on every tool call. Eliminates redundant process spawns, consolidates jq invocations, and backgrounds the tty write to remove render-pressure spikes.Benchmark (Apple M3 Pro, macOS 15.4)
Measured with
hyperfine --warmup 5 --runs 50.Changes
perf: add early exit for non-Warp environmentsexit 0before sourcing anythingperf: inline OSC 777 writeperf: collapse 4 jq invocations into single passjq -ncreads stdin and builds payloadperf: background tty writefix: validate protocol version, trailing slash, empty payload guardtest: add unit tests for on-post-tool-use.shWhat each change does
sourceorSCRIPT_DIRresolution. Non-Warp environments (subagents, CI) exit in ~1ms.warp-notify.shwhich re-sourcedshould-use-structured.shand re-ran the gate. Saves a bash spawn + redundant function call.build_payload+ 1 fortool_name) with a singlejq -ncthat reads stdin and constructs the full payload. Protocol negotiation inlined as bash arithmetic.printf > /dev/ttyto prevent synchronous blocking when Warp's PTY is congested during heavy screen rendering.scriptcommand to capture/dev/ttyoutput.Design decisions
build-payload.sh(protocol negotiation, payload structure). Acceptable because it's the only hot-path hook (~20 calls/session vs 1-2 for others), and the shared files remain for other hooks.should_use_structuredkept for version gate: The early env var check is a fast-path for non-Warp environments only. The full function call remains to handle broken Warp builds that set the env var but can't render structured notifications.Reproduce the benchmark
Requires hyperfine (
brew install hyperfine).Generated by Codeflash Agent
Test plan
bash plugins/warp/tests/test-hooks.shpasses (56/56)